home *** CD-ROM | disk | FTP | other *** search
/ Utilities Professional 1-1500 / Utilities Professional 1-1500 (1994)(WPD)[!].iso / 12511500 / var1273.dms / var1273.adf / AmiCDROM / cdrom.c < prev    next >
C/C++ Source or Header  |  1992-09-02  |  13KB  |  480 lines

  1. /* cdrom.c:
  2.  *
  3.  * Basic interaction with the CDROM drive.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1993 by Frank Munkert.
  7.  * All rights reserved.
  8.  * This software may be freely distributed and redistributed for
  9.  * non-commercial purposes, provided this notice is included.
  10.  * ----------------------------------------------------------------------
  11.  * History:
  12.  * 
  13.  * 06-Dec-93   fmu   New drive type DRIVE_SCSI_2.
  14.  * 09-Nov-93   fmu   Added Select_XA_Mode.
  15.  * 23-Oct-93   fmu   Open_CDROM now returns an error code that tell what
  16.  *                   went wrong.
  17.  * 09-Oct-93   fmu   SAS/C support added.
  18.  * 03-Oct-93   fmu   New buffering algorithm.
  19.  * 27-Sep-93   fmu   Added support for multi-LUN devices.
  20.  * 24-Sep-93   fmu   - SCSI buffers may now reside in fast or chip memory.
  21.  *                   - TD_CHANGESTATE instead of CMD_READ in Test_Unit_Ready
  22.  */
  23.  
  24. #include <string.h>
  25.  
  26. #include <clib/exec_protos.h>
  27. #include <clib/alib_protos.h>
  28.  
  29. #ifdef AZTEC_C
  30. #include <pragmas/exec_lib.h>
  31. #endif
  32. #ifdef LATTICE
  33. #include <pragmas/exec_pragmas.h>
  34. #endif
  35. #if defined (_DCC) && defined (REGISTERED)
  36. #include <pragmas/exec_pragmas.h>
  37. #endif
  38.  
  39. #include <devices/trackdisk.h>
  40.  
  41. #include <limits.h>
  42.  
  43. #include "cdrom.h"
  44.  
  45. int g_cdrom_errno;
  46.  
  47. void Determine_Drive_Type (CDROM *p_cd)
  48. {
  49.   t_inquiry_data data;
  50.   char buf[33];
  51.   
  52.   p_cd->drive_type = DRIVE_ANY;
  53.  
  54.   if (!Inquire (p_cd, &data))
  55.     return;
  56.  
  57.   if ((data.version & 0x7) >= 2)
  58.     p_cd->drive_type = DRIVE_SCSI_2;
  59.  
  60.   if (strncmp (data.vendor, "TOSHIBA", 7))
  61.     return;
  62.  
  63.   memcpy (buf, data.product, 32);
  64.   buf[32] = 0;
  65.   
  66.   if (strstr (buf, "3401"))
  67.     p_cd->drive_type = DRIVE_TOSHIBA_3401;
  68. }
  69.  
  70. CDROM *Open_CDROM (char *p_device, int p_scsi_id, int p_use_trackdisk,
  71.            int p_use_fast_mem, int p_std_buffers, int p_file_buffers)
  72. {
  73.   CDROM *cd;
  74.   int i;
  75.   int bufs = p_std_buffers + p_file_buffers + 1;
  76.   
  77.   g_cdrom_errno = CDROMERR_NO_MEMORY;
  78.  
  79.   cd = AllocMem (sizeof (CDROM),
  80.                MEMF_PUBLIC | MEMF_CLEAR |
  81.          (p_use_fast_mem ? MEMF_FAST : MEMF_CHIP));
  82.   if (!cd)
  83.     return NULL;
  84.  
  85.   cd->buffer_data = AllocMem (SCSI_BUFSIZE * bufs + 15,
  86.                     MEMF_PUBLIC |
  87.                   (p_use_fast_mem ? MEMF_FAST : MEMF_CHIP));
  88.   if (!cd->buffer_data) {
  89.     FreeMem (cd, sizeof (CDROM));
  90.     return NULL;
  91.   }
  92.  
  93.   cd->buffers = AllocMem (sizeof (unsigned char *) * bufs, MEMF_PUBLIC);
  94.   if (!cd->buffers) {
  95.     FreeMem (cd->buffer_data, SCSI_BUFSIZE * bufs + 15);
  96.     FreeMem (cd, sizeof (CDROM));
  97.     return NULL;
  98.   }
  99.   
  100.   cd->current_sectors = AllocMem (sizeof (long) * bufs, MEMF_PUBLIC);
  101.   if (!cd->current_sectors) {
  102.     FreeMem (cd->buffers, sizeof (unsigned char *) * bufs);
  103.     FreeMem (cd->buffer_data, SCSI_BUFSIZE * bufs + 15);
  104.     FreeMem (cd, sizeof (CDROM));
  105.     return NULL;
  106.   }
  107.  
  108.   cd->last_used = AllocMem (sizeof (unsigned long) * p_std_buffers,
  109.                   MEMF_PUBLIC | MEMF_CLEAR);
  110.   if (!cd->last_used) {
  111.     FreeMem (cd->current_sectors, sizeof (long) * bufs);
  112.     FreeMem (cd->buffers, sizeof (unsigned char *) * bufs);
  113.     FreeMem (cd->buffer_data, SCSI_BUFSIZE * bufs + 15);
  114.     FreeMem (cd, sizeof (CDROM));
  115.     return NULL;
  116.   }
  117.   
  118.   /* make the buffer quad-word aligned. This greatly helps 
  119.    * performance on '040-powered systems with DMA SCSI
  120.    * controllers.
  121.    */
  122.  
  123.   cd->buffers[0] = (UBYTE *)(((ULONG)cd->buffer_data + 15) & ~15);
  124.  
  125.   for (i=1; i<bufs; i++)
  126.     cd->buffers[i] = cd->buffers[0] + i * SCSI_BUFSIZE;
  127.  
  128.   cd->port = CreateMsgPort ();
  129.   if (!cd->port) {
  130.     g_cdrom_errno = CDROMERR_MSGPORT;
  131.     FreeMem (cd->last_used, sizeof (unsigned long) * p_std_buffers);
  132.     FreeMem (cd->current_sectors, sizeof (long) * bufs);
  133.     FreeMem (cd->buffers, sizeof (unsigned char *) * bufs);
  134.     FreeMem (cd->buffer_data, SCSI_BUFSIZE * bufs + 15);
  135.     FreeMem (cd, sizeof (CDROM));
  136.     return NULL;
  137.   }
  138.  
  139.   cd->scsireq = CreateIORequest (cd->port, sizeof (struct IOStdReq));
  140.   if (!cd->scsireq) {
  141.     g_cdrom_errno = CDROMERR_IOREQ;
  142.     DeleteMsgPort (cd->port);
  143.     FreeMem (cd->last_used, sizeof (unsigned long) * p_std_buffers);
  144.     FreeMem (cd->current_sectors, sizeof (long) * bufs);
  145.     FreeMem (cd->buffers, sizeof (unsigned char *) * bufs);
  146.     FreeMem (cd->buffer_data, SCSI_BUFSIZE * bufs + 15);
  147.     FreeMem (cd, sizeof (CDROM));
  148.     return NULL;
  149.   }
  150.  
  151.   if (OpenDevice ((UBYTE *) p_device, p_scsi_id,
  152.                   (struct IORequest *) cd->scsireq, 0)) {
  153.     g_cdrom_errno = CDROMERR_DEVICE;
  154.     DeleteIORequest (cd->scsireq);
  155.     DeleteMsgPort (cd->port);
  156.     FreeMem (cd->last_used, sizeof (unsigned long) * p_std_buffers);
  157.     FreeMem (cd->current_sectors, sizeof (long) * bufs);
  158.     FreeMem (cd->buffers, sizeof (unsigned char *) * bufs);
  159.     FreeMem (cd->buffer_data, SCSI_BUFSIZE * bufs + 15);
  160.     FreeMem (cd, sizeof (CDROM));
  161.     return NULL;
  162.   }
  163.  
  164.   for (i=0; i<bufs; i++)
  165.     cd->current_sectors[i] = -1;
  166.   
  167.   cd->use_trackdisk = p_use_trackdisk;
  168.  
  169.   /* The LUN is the 2nd digit of the SCSI id number: */
  170.   cd->lun = (p_scsi_id / 10) % 10;
  171.  
  172.   cd->std_buffers = p_std_buffers;
  173.   cd->file_buffers = p_file_buffers;
  174.   
  175.   /* 'tick' is incremented every time a sector is accessed. */
  176.   cd->tick = 0;
  177.  
  178.   g_cdrom_errno = 0;
  179.  
  180.   Determine_Drive_Type (cd);
  181.  
  182.   return cd;
  183. }
  184.  
  185. int Do_SCSI_Command (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  186.              unsigned char *p_command, int p_length)
  187. {
  188.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  189.  
  190.   p_cd->scsireq->io_Length   = sizeof (struct SCSICmd);
  191.   p_cd->scsireq->io_Data     = (APTR) &p_cd->cmd;
  192.   p_cd->scsireq->io_Command  = HD_SCSICMD;
  193.  
  194.   p_cd->cmd.scsi_Data        = (UWORD *) p_buf;
  195.   p_cd->cmd.scsi_Length      = p_buf_length;
  196.   p_cd->cmd.scsi_Flags       = SCSIF_AUTOSENSE | SCSIF_READ;
  197.   p_cd->cmd.scsi_SenseData   = (UBYTE *) p_cd->sense;
  198.   p_cd->cmd.scsi_SenseLength = 18;
  199.   p_cd->cmd.scsi_SenseActual = 0;
  200.   p_cd->cmd.scsi_Command     = (UBYTE *) p_command;
  201.   p_cd->cmd.scsi_CmdLength   = p_length;
  202.  
  203.   p_command[1] |= p_cd->lun << 5;
  204.  
  205.   DoIO ((struct IORequest *) p_cd->scsireq);
  206.   if (p_cd->cmd.scsi_Status) {
  207.     int i;
  208.     for (i=0; i<bufs; i++)
  209.       p_cd->current_sectors[i] = -1;
  210.     return 0;
  211.   } else
  212.     return 1;
  213. }
  214.  
  215. int Read_From_Drive (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  216.              long p_sector, int p_number_of_sectors)
  217. {
  218.   static unsigned char cmd[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  219.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  220.  
  221. #ifdef DEBUG_SECTORS
  222.   extern void *dbprintf (char *, ...);
  223.  
  224.   if (p_number_of_sectors == 1)
  225.     dbprintf ("[%ld]", p_sector);
  226.   else
  227.     dbprintf ("[%ld-%ld]", p_sector, p_sector + p_number_of_sectors - 1);
  228. #endif
  229.  
  230.   if (p_cd->use_trackdisk) {
  231.     p_cd->scsireq->io_Length   = 2048 * p_number_of_sectors;
  232.     p_cd->scsireq->io_Data     = (APTR) p_buf;
  233.     p_cd->scsireq->io_Offset   = (ULONG) p_sector * 2048;
  234.     p_cd->scsireq->io_Command  = CMD_READ;
  235.  
  236.     DoIO ((struct IORequest *) p_cd->scsireq);
  237.     if (p_cd->scsireq->io_Error) {
  238.       int i;
  239.       for (i=0; i<bufs; i++)
  240.         p_cd->current_sectors[i] = -1;
  241.       return 0;
  242.     } else
  243.       return 1;
  244.   } else {
  245.     cmd[5] = p_sector & 0xff;
  246.     cmd[4] = (p_sector >> 8) & 0xff;
  247.     cmd[3] = (p_sector >> 16) & 0x1f;
  248.  
  249.     cmd[8] = p_number_of_sectors;
  250.   
  251.     return Do_SCSI_Command (p_cd, p_buf, p_buf_length, cmd, sizeof (cmd));
  252.   }
  253. }
  254.  
  255. /* Read one sector from the CDROM drive.
  256.  */
  257.  
  258. int Read_Sector (CDROM *p_cd, long p_sector)
  259. {
  260.   int status;
  261.   int i;
  262.   int maxbuf = p_cd->std_buffers;
  263.   int loc;
  264.  
  265.   p_cd->tick++;
  266.  
  267.   for (i=0; i<maxbuf; i++)
  268.     if (p_cd->current_sectors[i] == p_sector) {
  269.       p_cd->buffer = p_cd->buffers[i];
  270.       p_cd->last_used[i] = p_cd->tick;
  271.       return 1;
  272.     }
  273.  
  274.   /* find an empty buffer position: */
  275.   for (loc=0; loc<maxbuf; loc++)
  276.     if (p_cd->current_sectors[loc] == -1)
  277.       break;
  278.  
  279.   if (loc==maxbuf) {
  280.     /* no free buffer position; remove the buffer that is unused
  281.        for the longest time: */
  282.     unsigned long oldest_tick = ULONG_MAX;
  283.     unsigned long tick;
  284.  
  285.     for (loc=0, i=0; i<maxbuf; i++) {
  286.       tick = p_cd->last_used[i];
  287.       if (tick < oldest_tick)
  288.         loc = i, oldest_tick = tick;
  289.     }
  290.   }
  291.  
  292.   status = Read_From_Drive (p_cd, p_cd->buffers[loc], SCSI_BUFSIZE,
  293.                   p_sector, 1);
  294.   if (status) {
  295.     p_cd->current_sectors[loc] = p_sector;
  296.     p_cd->buffer = p_cd->buffers[loc];
  297.     p_cd->last_used[loc] = p_cd->tick;
  298.   }
  299.  
  300.   return status;
  301. }
  302.  
  303. /* Read_Contiguous_Sectors uses the 'file buffers' instead of the
  304.  * 'standard buffers'. Additionaly, more than one sector may be read
  305.  * with a single SCSI command. This may cause a substantial increase
  306.  * in speed when reading large files.
  307.  */
  308.  
  309. int Read_Contiguous_Sectors (CDROM *p_cd, long p_sector, long p_last_sector)
  310. {
  311.   int status;
  312.   int i;
  313.   int maxbuf = p_cd->std_buffers + p_cd->file_buffers;
  314.   int len;
  315.  
  316.   for (i=p_cd->std_buffers; i<maxbuf; i++)
  317.     if (p_cd->current_sectors[i] == p_sector) {
  318.       p_cd->buffer = p_cd->buffers[i];
  319.       return 1;
  320.     }
  321.  
  322.   if (p_last_sector <= p_sector)
  323.     len = 1;
  324.   else {
  325.     len = p_last_sector - p_sector + 1;
  326.     if (len > p_cd->file_buffers)
  327.       len = p_cd->file_buffers;
  328.   }
  329.  
  330.   status = Read_From_Drive (p_cd, p_cd->buffers[p_cd->std_buffers],
  331.                   SCSI_BUFSIZE * len, p_sector, len);
  332.   if (status) {
  333.     long sector = p_sector;
  334.     for (i=p_cd->std_buffers; len; i++, len--)
  335.       p_cd->current_sectors[i] = sector++;
  336.     p_cd->buffer = p_cd->buffers[p_cd->std_buffers];
  337.   }
  338.  
  339.   return status;
  340. }
  341.  
  342. int Test_Unit_Ready (CDROM *p_cd)
  343. {
  344.   if (p_cd->use_trackdisk) {
  345.     p_cd->scsireq->io_Command = TD_CHANGESTATE;
  346.  
  347.     if (!DoIO ((struct IORequest *) p_cd->scsireq)) {
  348.       if (!p_cd->scsireq->io_Actual)
  349.         return 1;
  350.     }
  351.     return 0;
  352.   } else {
  353.     int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  354.     static unsigned char cmd[6] = { 0, 0, 0, 0, 0, 0 };
  355.  
  356.     return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  357.                     cmd, 6);
  358.   }
  359. }
  360.  
  361. int Is_XA_Mode_Disk (CDROM *p_cd)
  362. {
  363.   static unsigned char cmd[10] = { 0xC7, 3, 0, 0, 0, 0, 0, 0, 0, 0 };
  364.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  365.  
  366.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  367.               cmd, 10))
  368.     return FALSE;
  369.  
  370.   return *(p_cd->buffers[dummy_buf]) == 0x20;
  371. }
  372.  
  373. int Select_XA_Mode (CDROM *p_cd, int p_on)
  374. {
  375.   static unsigned char cmd[6] = { 0x15, 0x10, 0, 0, 12, 0 };
  376.   static unsigned char mode[12] = { 0, 0, 0, 8,
  377.                     0, 0, 0, 0, 0, 0, 0x8, 0 };
  378.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  379.  
  380.   if (p_cd->use_trackdisk || p_cd->drive_type != DRIVE_TOSHIBA_3401)
  381.     return FALSE;
  382.   
  383.   mode[4] = p_on ? 0x81 : 0;
  384.  
  385.   memcpy (p_cd->buffers[dummy_buf], mode, sizeof (mode));
  386.   return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  387.                 cmd, 6);  
  388. }
  389.  
  390. int Inquire (CDROM *p_cd, t_inquiry_data *p_data)
  391. {
  392.   static unsigned char cmd[6] = { 0x12, 0, 0, 0, 96, 0 };
  393.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  394.   
  395.   if (p_cd->use_trackdisk)
  396.     return FALSE;
  397.  
  398.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  399.               cmd, 6))
  400.     return FALSE;
  401.   
  402.   memcpy (p_data, p_cd->buffers[dummy_buf], sizeof (*p_data));
  403.   return 1;
  404. }
  405.  
  406. t_toc_data *Read_TOC (CDROM *p_cd, t_toc_header *p_toc_header)
  407. {
  408.   static unsigned char cmd[10] = { 0x43, 0, 0, 0, 0, 0, 1, 8, 0, 0 };
  409.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  410.  
  411.   if (p_cd->use_trackdisk)
  412.     return NULL;
  413.  
  414.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  415.               cmd, 10))
  416.     return NULL;
  417.  
  418.   memcpy (p_toc_header, p_cd->buffers[dummy_buf], sizeof (*p_toc_header));
  419.   return (t_toc_data *) (p_cd->buffers[dummy_buf] + 4);
  420. }
  421.  
  422. int Has_Audio_Tracks (CDROM *p_cd)
  423. {
  424.   t_toc_header hdr;
  425.   t_toc_data *toc;
  426.   int i, len;
  427.   
  428.   if (!(toc = Read_TOC (p_cd, &hdr)))
  429.     return FALSE;
  430.  
  431.   len = hdr.length / 8;
  432.   for (i=0; i<len; i++) {
  433.     if (toc[i].track_number != 0xAA &&
  434.         !(toc[i].flags & 4))
  435.       return toc[i].track_number;
  436.   }
  437.   return FALSE;
  438. }
  439.  
  440. int Start_Play_Audio (CDROM *p_cd)
  441. {
  442.   static unsigned char cmd[10] = { 0x48, 0, 0, 0, 0, 1, 0, 0, 1, 0 };
  443.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  444.  
  445.   if (p_cd->use_trackdisk || p_cd->drive_type == DRIVE_ANY)
  446.     return FALSE;
  447.  
  448.   cmd[4] = Has_Audio_Tracks (p_cd);
  449.   cmd[7] = cmd[4];
  450.  
  451.   return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  452.                     cmd, 10);
  453. }
  454.  
  455. int Stop_Play_Audio (CDROM *p_cd)
  456. {
  457.   static unsigned char cmd[6] = { 0x1B, 0, 0, 0, 0, 0 };
  458.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  459.  
  460.   if (p_cd->use_trackdisk || p_cd->drive_type == DRIVE_ANY)
  461.     return FALSE;
  462.  
  463.   return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  464.                     cmd, 6);
  465. }
  466.  
  467. void Cleanup_CDROM (CDROM *p_cd)
  468. {
  469.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  470.  
  471.   CloseDevice ((struct IORequest *) p_cd->scsireq);
  472.   DeleteIORequest (p_cd->scsireq);
  473.   DeleteMsgPort (p_cd->port);
  474.   FreeMem (p_cd->last_used, sizeof (unsigned long) * p_cd->std_buffers);
  475.   FreeMem (p_cd->current_sectors, sizeof (long) * bufs);
  476.   FreeMem (p_cd->buffers, sizeof (unsigned char *) * bufs);
  477.   FreeMem (p_cd->buffer_data, SCSI_BUFSIZE * bufs + 15);
  478.   FreeMem (p_cd, sizeof (CDROM));
  479. }
  480.